package com.tanvir.ojdeploy.ant;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import java.util.ArrayList;
import java.util.List;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.ExecTask;
import org.apache.tools.ant.types.Commandline.Argument;


public class OJDeployTask extends ExecTask {
    private String executable;
    private File projectsfile;
    private File basedir;
    private List<WorkspaceTask> workspaces = new ArrayList<WorkspaceTask>();

    public OJDeployTask(org.apache.tools.ant.Task task) {
        super(task);
    }

    public OJDeployTask() {
        super();
    }

    @Override
    public void execute() throws BuildException {
        log("Starting OJdeploy");
        //Add from projectfile attribute
        if (projectsfile != null && projectsfile.canRead()) {
            BufferedReader br = null;
            try {
                br = new BufferedReader(new FileReader(projectsfile));
                String line = null;
                while ((line = br.readLine()) != null) {
                    if (line.length() <= 0 || line.startsWith("#")) {
                        continue;
                    }
                    String[] split = line.split(",", -1);
                    if (split == null || split.length < 7) {
                        log("Error while executing line " + line);
                        continue;
                    }
                    if (isEmpty(split[0]) || isEmpty(split[2])) {
                        log("Either workspace or profile is missing in " +
                            line);
                        continue;
                    }
                    WorkspaceTask wt = createWorkspace();
                    wt.bindToOwner(this);
                    ProjectTask pt = null;
                    wt.setPath(split[0]);
                    if (!isEmpty(split[3])) {
                        wt.setClean(Boolean.parseBoolean(split[3]));
                    }
                    if (!isEmpty(split[4])) {
                        wt.setNocompile(Boolean.parseBoolean(split[4]));
                    }
                    if (wt.clean && wt.nocompile) {
                        throw new BuildException("cannot set clean and nocompile 'true' togeather in : " +
                                                 line);
                    }
                    if (!isEmpty(split[5])) {
                        wt.setOutputfile(new File(split[5]));
                    }
                    if (!isEmpty(split[6])) {
                        wt.setLogfile(new File(split[6]));
                    }
                    if (!isEmpty(split[1])) {
                        pt = wt.createProject();
                        pt.bindToOwner(wt);
                    }
                    if (pt != null) {
                        pt.setName(split[1]);
                        pt.setProfile(split[2]);
                    } else {
                        wt.setProfile(split[2]);
                    }
                }
            } catch (Exception e) {
                throw new BuildException(e);
            } finally {
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException ioe) {
                        log("Error closing projectsfile");
                    }
                }
            }
        }

        //Add from workspace inner tasks
        if (!workspaces.isEmpty()) {
            for (WorkspaceTask wt : workspaces) {
                log("Executing workspace : " + wt.path);
                if (!wt.projects.isEmpty()) {
                    for (ProjectTask pt : wt.projects) {
                        ExecTask et = buildTask(pt);
                        et.execute();
                    }
                }
                if (wt.profile != null) {
                    ExecTask et = buildTask(wt);
                    et.execute();
                }
            }
        }

        log("Finished OJdeploy");
    }

    private boolean isEmpty(String s) {
        return s == null || s.trim().length() <= 0;
    }

    private ExecTask buildTask(WorkspaceTask task) {
        ProjectTask pt = null;
        if (task instanceof ProjectTask) {
            pt = (ProjectTask)task;
        }
        ExecTask et = new ExecTask(pt != null ? pt : task);
        et.bindToOwner(pt != null ? pt : task);
        et.setExecutable(executable);
        et.setFailonerror(failOnError);
        StringBuilder args = new StringBuilder();
        if (task.nocompile && task.clean) {
            throw new BuildException("cannot set clean and nocompile 'true' togeather");
        }
        args.append(task.nocompile ? "-nocompile " : "");
        args.append(task.clean ? "-clean " : "");
        if (isEmpty(task.path)) {
            throw new BuildException("path is required.");
        }
        File wsPath = new File(basedir, task.path);
        if (wsPath == null || !wsPath.exists() || !wsPath.canRead()) {
            throw new BuildException("path " + wsPath.getAbsolutePath() +
                                     " not found.");
        }
        args.append("-workspace " + task.path + " ");
        if (pt != null) {
            args.append("-project " + pt.name + " ");
        }
        args.append("-profile " + task.profile + " ");
        args.append("-basedir " + basedir + " ");
        args.append(task.outputfile != null ?
                    "-outputfile " + task.outputfile.getAbsolutePath() + " " :
                    "");
        args.append(task.logfile != null ?
                    "-statuslogfile " + task.logfile.getAbsolutePath() + " " :
                    "");
        Argument argument = et.createArg();
        argument.setLine(args.toString());
        log("about to execute ojdeploy with args = " + args.toString());
        return et;
    }

    @Override
    public void setExecutable(String executable) {
        this.executable = executable;
    }

    @Override
    public void setFailonerror(boolean b) {
        super.setFailonerror(b);
    }

    public void setProjectsfile(File projectsfile) {
        this.projectsfile = projectsfile;
    }

    public void setBasedir(File basedir) {
        if (basedir == null) {
            throw new BuildException("basedir is required.");
        }
        if (!basedir.isDirectory()) {
            throw new BuildException("basedir must be a valid directory");
        }
        this.basedir = basedir;
    }

    public WorkspaceTask createWorkspace() {
        WorkspaceTask wt = new WorkspaceTask();
        workspaces.add(wt);
        return wt;
    }

    public class WorkspaceTask extends Task {
        private String path;
        private String profile;
        private boolean clean = true;
        private boolean nocompile = false;
        private File outputfile;
        private File logfile;
        private List<ProjectTask> projects = new ArrayList<ProjectTask>();

        public void setPath(String path) {
            this.path = path;
        }

        public void setProfile(String profile) {
            this.profile = profile;
        }

        public void setClean(boolean clean) {
            this.clean = clean;
        }

        public void setOutputfile(File outputfile) {
            this.outputfile = outputfile;
        }

        public ProjectTask createProject() {
            ProjectTask pt = new ProjectTask();
            pt.setPath(path);
            pt.setClean(clean);
            pt.setNocompile(nocompile);
            pt.setOutputfile(outputfile);
            pt.setLogfile(logfile);
            projects.add(pt);
            return pt;
        }

        public void setNocompile(boolean nocompile) {
            this.nocompile = nocompile;
        }

        public void setLogfile(File logfile) {
            this.logfile = logfile;
        }

        @Override
        public String getTaskName() {
            return "workspace";
        }
    }

    public class ProjectTask extends WorkspaceTask {
        private String name;

        @Override
        public void setClean(boolean clean) {
            super.setClean(clean);
        }

        @Override
        public void setOutputfile(File outputfile) {
            super.setOutputfile(outputfile);
        }

        @Override
        public void setProfile(String profile) {
            super.setProfile(profile);
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String getTaskName() {
            return "project";
        }
    }
}
